package com.thx;


import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Properties;

import javax.inject.Inject;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import com.thx.common.Constant;
import com.thx.user.DatabaseAuthenticationProvider;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletContextInitializer;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import com.thx.common.Constant;
import com.thx.web.filter.WebSessionFilter;

//mvn -Dexec.classpathScope=test test-compile spring-boot:run
//mvn -Dexec.classpathScope=test -Pintegration  spring-boot:run

@SpringBootApplication
public class AuthWebApplication extends SpringBootServletInitializer implements ServletContextInitializer {

    private static final Logger log = LoggerFactory.getLogger(AuthWebApplication.class);

    @Inject
    private Environment env;

    /**
     * Main method, used to run the application.
     */
    public static void main(String[] args) throws UnknownHostException {
        SpringApplication app = new SpringApplication(AuthWebApplication.class);
        SimpleCommandLinePropertySource source = new SimpleCommandLinePropertySource(args);
        addDefaultProfile(app, source);

        Environment env = app.run(args).getEnvironment();
        log.info("Access URLs:\n----------------------------------------------------------\n\t" +
                        "Local: \t\thttp://localhost:{}{}\n\t" +
                        "External: \thttp://{}:{}{}\n----------------------------------------------------------",
                env.getProperty("server.port"),
                env.getProperty("server.contextPath"),
                InetAddress.getLocalHost().getHostAddress(),
                env.getProperty("server.port"),
                env.getProperty("server.contextPath"));

    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        log.info("开始 Web 应用配置, profiles: {}", Arrays.toString(env.getActiveProfiles()));
        EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);

        // 初始化 OpenSessionInView
        initOpenSessionInViewFilter(servletContext, disps);

        //初始化 WebSessionFilter
        initWebSessionFilter(servletContext, disps);

        // 初始化 struts2
        initStruts2Filter(servletContext, disps);

        log.info("Web 应用已配置完成");
    }

//    /**
//     * 设定 Mime types.
//     */
//    @Override
//    public void customize(ConfigurableEmbeddedServletContainer container) {
//        MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
//        // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711
//        mappings.add("html", "text/html;charset=utf-8");
//        // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64
////        mappings.add("json", "text/html;charset=utf-8");
//        container.setMimeMappings(mappings);
//    }

    /**
     * 设定 Struts2 过滤器
     *
     * @param servletContext
     * @param disps
     */
    private void initStruts2Filter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
        log.info("初始化 Struts2 过滤器");
        FilterRegistration.Dynamic filter = servletContext.addFilter("struts2", new StrutsPrepareAndExecuteFilter());

        filter.setInitParameter("actionPackages", "com.com.thx.org.action,com.com.thx.privilege.action,com.com.thx.resource.action,com.com.thx.role.action,com.com.thx.user.action,com.com.thx.web.action");
        filter.addMappingForUrlPatterns(disps, true, "*.action");
        filter.addMappingForUrlPatterns(disps, true, "/config-browser/*");
        filter.addMappingForUrlPatterns(disps, true, "/config-browser/");
    }

    /**
     * 设定 OpenSessionInView 过滤器
     * @param servletContext
     * @param disps
     */
    private void initOpenSessionInViewFilter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
        log.info("初始化 OpenSessionInView 过滤器");
        FilterRegistration.Dynamic filter = servletContext.addFilter("OpenSessionInViewFilter", new OpenSessionInViewFilter());

        filter.addMappingForUrlPatterns(disps, true, "*.action");
        filter.addMappingForUrlPatterns(disps, true, "*.jsp");
    }

    /**
     * 设定 OpenSessionInView 过滤器
     * @param servletContext
     * @param disps
     */
    private void initWebSessionFilter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
        log.info("初始化 WebSessionFilter 过滤器");
        FilterRegistration.Dynamic filter = servletContext.addFilter("sessionFilter", new WebSessionFilter());

        filter.setInitParameter("excludePaths", "login.jsp,login!input.action,login!logon.action,captcha.action,checkUserName.action,doNewHtml5New.action,doNewHtml5List.action");
        filter.setInitParameter("failGo", "failGo.html");
        filter.addMappingForUrlPatterns(disps, true, "*.action");
        filter.addMappingForUrlPatterns(disps, true, "*.jsp");
    }

    /**
     * If no profile has been configured, set by default the "dev" profile.
     */
    private static void addDefaultProfile(SpringApplication app, SimpleCommandLinePropertySource source) {
        if (!source.containsProperty("spring.profiles.active") &&
                !System.getenv().containsKey("SPRING_PROFILES_ACTIVE")) {

            app.setAdditionalProfiles(Constant.SPRING_PROFILE_DEVELOPMENT);
        }
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(AuthWebApplication.class);
    }

    @Bean
    public HibernateJpaSessionFactoryBean sessionFactory() {
        return new HibernateJpaSessionFactoryBean();
    }



    /**
     * 安全配置
     */
    @EnableWebSecurity(debug = false)
    public static class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(inMemoryUserDetailsManager());
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring()
                    .antMatchers("/css/**/*", "/images/**/*", "/scripts/**/*", "/fonts/**/*", "/lib/**/*");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable() // 允许直接提交
                    .formLogin()
                    .loginPage("/pages/system/common/login.jsp")
                    .defaultSuccessUrl("/pages/index.jsp", false)
                    .usernameParameter("username")
                    .passwordParameter("passwd")
                    .permitAll()
                    .and()
                    .authenticationProvider(authenticationProvider())
                    .requestMatchers()
                    .antMatchers("/**")
                    .and()
                    .authorizeRequests()
                    .anyRequest().permitAll();
//                    .authenticated(); // 临时关闭安全验证
        }

        @Bean
        public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
            final Properties users = new Properties();
            users.put("psl", "123456,ROLE_USER,enabled");
            users.put("admin", "123456,ROLE_ADMIN,enabled");
            return new InMemoryUserDetailsManager(users);
        }

        @Bean
        public AuthenticationProvider authenticationProvider() {
            return new DatabaseAuthenticationProvider();
        }
    }

}
